package com.hymjweb.demo.framework.util;

import lombok.extern.slf4j.Slf4j;
import org.abego.treelayout.internal.util.java.util.ListUtil;

import java.lang.reflect.Field;
import java.text.NumberFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * @BelongsProject: demo
 * @BelongsPackage: com.hymjweb.demo.framework.util
 * @Author: luoge
 * @CreateTime: 2021-03-18 15:09
 * @Description:
 * 至少需要满足以下5点：
 * ①.list元素对象类型任意   ---->使用泛型解决
 * ②.可以按照list元素对象的任意多个属性进行排序,即可以同时指定多个属性进行排序  --->使用java的可变参数解决
 * ③.list元素对象属性的类型可以是数字(byte、short、int、long、float、double等，包括正数、负数、0)、字符串(char、String)、日期(java.util.Date)
 *          --->对于数字：统一转换为固定长度的字符串解决,比如数字3和123，转换为"003"和"123" 再比如"-15"和"7"转换为"-015"和"007"
 *          --->对于日期：可以先把日期转化为long类型的数字，数字的解决方法如上
 * ④.list元素对象的属性可以没有相应的getter和setter方法
 *          --->可以使用java反射进行获取private和protected修饰的属性值
 * ⑤.list元素对象的对象的每个属性都可以指定是升序还是降序
 *          -->使用2个重写的方法(一个方法满足所有属性都按照升序(降序)，另外一个方法满足每个属性都能指定是升序(降序))
 */
@Slf4j
public class ListSortUtil {

    public static <E> void sort(List<E> list, final boolean isAsc, final String... sortNameArr){
        Collections.sort(list, new Comparator<E>() {
            @Override
            public int compare(E o1, E o2) {
                int ret = 0;
                try {
                    for(int i=0;i<sortNameArr.length;i++){
                        ret = ListSortUtil.compareObject(sortNameArr[i],isAsc,o1,o2);
                        if(0!=ret){
                            break;
                        }
                    }
                }catch (Exception e){
                    log.info(e.getMessage());
                }
                return ret;
            }
        });
    }

    public static <E> void sort(List<E> list, final String[] sortNameArr, final boolean[] typeArr){
        if(sortNameArr.length != typeArr.length){
            throw new RuntimeException("属性数组元素个数和升降序数组元素个数不相等");
        }

        Collections.sort(list, new Comparator<E>() {
            @Override
            public int compare(E o1, E o2) {
                int ret = 0;
                try {
                    for(int i = 0; i<sortNameArr.length; i++){
                        ret = ListSortUtil.compareObject(sortNameArr[i],typeArr[i],o1,o2);
                        if(0 != ret){
                            break;
                        }
                    }
                }catch (Exception e){
                    log.info(e.getMessage());
                }
                return ret;
            }
        });
    }

    private static <E> int compareObject(String sortName, boolean isAsc, E o1, E o2) throws NoSuchFieldException, IllegalAccessException {
        int ret;
        Object value1 = ListSortUtil.forceGetFieldValue(o1,sortName);
        Object value2 = ListSortUtil.forceGetFieldValue(o2,sortName);
        String str1 = value1.toString();
        String str2 = value2.toString();
        if(value1 instanceof Number && value2 instanceof Number){
            int maxLen = Math.max(str1.length(),str2.length());
            str1 = ListSortUtil.addZero2Str((Number)value1,maxLen);
            str2 = ListSortUtil.addZero2Str((Number)value2,maxLen);
        }
        else if(value1 instanceof Date && value2 instanceof Date){
            long time1 = ((Date)value1).getTime();
            long time2 = ((Date)value2).getTime();
            int maxLen = Long.toString(Math.max(time1,time2)).length();
            str1 = ListSortUtil.addZero2Str(time1,maxLen);
            str2 = ListSortUtil.addZero2Str(time2,maxLen);
        }

        if(isAsc){
            ret = str1.compareTo(str2);
        }
        else{
            ret = str2.compareTo(str1);
        }
        return ret;
    }

    private static String addZero2Str(Number numObj, int length) {
        NumberFormat nf = NumberFormat.getInstance();
        // 设置是否使用分组
        nf.setGroupingUsed(false);
        // 设置最大整数位数
        nf.setMaximumIntegerDigits(length);
        // 设置最小整数位数
        nf.setMinimumIntegerDigits(length);
        return nf.format(numObj);
    }

    private static <E> Object forceGetFieldValue(Object obj, String sortName) throws NoSuchFieldException, IllegalAccessException {
        Field field = obj.getClass().getField(sortName);
        Object object = null;
        boolean accessible = field.isAccessible();
        if(!accessible){
            // 如果是private,protected修饰的属性，需要修改为可以访问的
            field.setAccessible(true);
            object = field.get(obj);
            // 还原private,protected属性的访问性质
            field.setAccessible(accessible);
            return object;
        }
        obj = field.get(obj);
        return object;
    }

}
